package com.cloudtec.yunzonedep.config.mybatis;


import com.alibaba.druid.sql.SQLUtils;
import lombok.extern.slf4j.Slf4j;
import org.apache.ibatis.binding.MapperMethod.ParamMap;
import org.apache.ibatis.executor.Executor;
import org.apache.ibatis.mapping.BoundSql;
import org.apache.ibatis.mapping.MappedStatement;
import org.apache.ibatis.mapping.ParameterMapping;
import org.apache.ibatis.mapping.SqlCommandType;
import org.apache.ibatis.plugin.*;
import org.apache.ibatis.reflection.MetaObject;
import org.apache.ibatis.reflection.property.PropertyTokenizer;
import org.apache.ibatis.session.Configuration;
import org.apache.ibatis.session.ResultHandler;
import org.apache.ibatis.session.RowBounds;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;

import java.lang.reflect.Field;
import java.util.*;
import java.util.regex.Matcher;

/**
 * mybatis拦截器，
 *
 * @Author
 * @Date 2019-01-19
 */
@Slf4j
@Component
@Intercepts({@Signature(type = Executor.class, method = "update", args = {MappedStatement.class, Object.class}),
        @Signature(method = "query", type = Executor.class, args = {
                MappedStatement.class, Object.class, RowBounds.class,
                ResultHandler.class})})
public class MybatisInterceptor implements Interceptor {

    @Override
    public Object intercept(Invocation invocation) throws Throwable {
        //获取注解Signature中的参数的第一个，一般都是MappedStatement对象
        MappedStatement mappedStatement = (MappedStatement) invocation.getArgs()[0];
        //获取statementId
        String statementId = mappedStatement.getId();
        //System.out.println("========sqlId:" + statementId);
        //获取sql语句的操作模式：INSERT，DELETE，UPDATE，SELECT
        //SqlCommandType sqlCommandType = mappedStatement.getSqlCommandType();
        //System.out.println("语句模式："+sqlCommandType);
        Object parameter = null;
        //获取该Statement对应的输入的参数，参考sqlSession.insert(statement,param);
        //这里获取的就是要输入的参数，也对应Signature注解中的第二个参数Object.class
        if (invocation.getArgs().length > 1) {
            parameter = invocation.getArgs()[1];
        }
        //获取绑定的SQL
        BoundSql boundSql = mappedStatement.getBoundSql(parameter);
        log.info("要执行的SQL：{}", boundSql.getSql().replaceAll("\r|\n", ""));
        //获取配置对象
        Configuration configuration = mappedStatement.getConfiguration();
        //获取参数对象？
        Object parameterObject = boundSql.getParameterObject();
        //解析每一个参数
        List<ParameterMapping> paramsList = boundSql.getParameterMappings();
        if (paramsList != null && !paramsList.isEmpty()) {
            for (ParameterMapping pm : paramsList) {
                String propertyName = pm.getProperty();
                MetaObject metaObject = configuration.newMetaObject(parameterObject);
                Object propertyValue = boundSql.getAdditionalParameter(propertyName);
                if (metaObject.hasGetter(propertyName)) {
                    propertyValue = metaObject.getValue(propertyName);
                } else if (boundSql.hasAdditionalParameter(propertyName)) {
                    propertyValue = boundSql.getAdditionalParameter(propertyName);
                }
                //propertyValue.getClass().getName()
                log.info("参数：[{}={},({})]", propertyName, propertyValue,"");
            }
        }
        //System.out.println("要执行的SQL：" + boundSql.getSql().replaceAll("\r|\n", ""));
        Object result=invocation.proceed();

        return result;
    }

    @Override
    public Object plugin(Object target) {
        return Plugin.wrap(target, this);
    }

    @Override
    public void setProperties(Properties properties) {
        // TODO Auto-generated method stub
    }

    /**
     * 获取类的所有属性，包括父类
     *
     * @param object
     * @return
     */
    public static Field[] getAllFields(Object object) {
        Class<?> clazz = object.getClass();
        List<Field> fieldList = new ArrayList<>();
        while (clazz != null) {
            fieldList.addAll(new ArrayList<>(Arrays.asList(clazz.getDeclaredFields())));
            clazz = clazz.getSuperclass();
        }
        Field[] fields = new Field[fieldList.size()];
        fieldList.toArray(fields);
        return fields;
    }

}
